// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"

////////////////////////////////////////////////////////////////////////////////
class Noeud
{
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
public:
    virtual int  getValeur() =0 ; // méthode pure (non implémentée) qui rend la classe abstraite
    virtual void afficher(unsigned short indentation=0)
    {
        cout << setw(4*indentation) << " ";
    }
    // pour afficher un noeud avec un décalage (indentation) proportionnel à son niveau dans l'arbre

    virtual ~Noeud() {} // présence d'un destructeur virtuel conseillée dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud
{
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
public:
    NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction);  // ajoute une instruction à la séquence

private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud
{
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
public:
    NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurUnaire : public Noeud
{
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (non)
// et de 1 fils : l'opérande droit
public:
    NoeudOperateurUnaire(Symbole operateur, Noeud* operandeDroit);
    // construit une opération unaire : operateur OperandeDroit
    ~NoeudOperateurUnaire() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération

private:
    Symbole operateur;
    Noeud*  operandeDroit;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public Noeud
{
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération

private:
    Symbole operateur;
    Noeud*  operandeGauche;
    Noeud*  operandeDroit;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstSi : public Noeud
{
// classe pour représenter un noeud "instruction conditionnel si" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudInstSi();
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    NoeudInstSi(Noeud* s, Noeud* a, vector<Noeud*> sin);
    ~NoeudInstSi() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
    inline void ajouterSi(Noeud* inst)
    {
        this->si = inst;
    }
    inline void ajouterAlors(Noeud* inst)
    {
        this->alors = inst;
    }
    inline void ajouterSinon(Noeud* inst)
    {
        this->sinon.push_back(inst);
    }

private:
    Noeud*  si;
    Noeud*  alors;
    vector<Noeud*> sinon;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstTq : public Noeud
{
// classe pour représenter un noeud "instruction itérative tantQue" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudInstTq();
    NoeudInstTq(Noeud* cond, Noeud* seq);
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudInstTq() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
    void ajouterIter(Noeud* iter);
    void ajouterInst(Noeud* inst);

private:
    Noeud*  m_iter;
    Noeud*  m_inst;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstRepeter : public Noeud
{
// classe pour représenter un noeud "instruction itérative repeter" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudInstRepeter();
	NoeudInstRepeter(Noeud* cond, Noeud* seq);
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudInstRepeter() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération

private:
    Noeud*  m_iter;
    Noeud*  m_inst;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstPour : public Noeud
{
// classe pour représenter un noeud "instruction itérative pour" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudInstPour();
	NoeudInstPour(Noeud * i, Noeud* c, Noeud* it, Noeud* s);
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudInstPour() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération

private:
    Noeud*  init;
    Noeud*  cond;
	Noeud*  iter;
	Noeud*  seq;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstSelon : public Noeud
{
// classe pour représenter un noeud "instruction conditionnelle selon" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudInstSelon();
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudInstSelon() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération

private:
    Noeud*  si;
    Noeud*  alors;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstLire : public Noeud
{
// classe pour représenter un noeud "instruction lire" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudInstLire();
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudInstLire() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
    void ajouterSymboleValue(Noeud* val);

private:
    Noeud*  val;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstEcrire : public Noeud
{
// classe pour représenter un noeud "instruction ecrire" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
public:
    NoeudInstEcrire();
    // construit une opération binaire : operandeGauche operateur OperandeDroit
    ~NoeudInstEcrire() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
    void ajouterSymboleValue(Noeud* val);

private:
    Noeud*  val;
};


class NoeudSwitch : public Noeud {
public:
	NoeudSwitch(vector<Noeud*> ent, vector<Noeud*> seq, Noeud* var);

	~NoeudSwitch() {
	}
	int getValeur();
	void afficher(unsigned short indentation = 0);
private:
	vector<Noeud*> entiers;
	vector<Noeud*> sequence;
	Noeud* variable;
};
#endif /* ARBRE_H_ */
